<?php

namespace app\bll;

use app\validate\HookEvent as ValidateHookEvent;
use Exception;
use support\Db;

/**
 * 钩子事件
 */
class HookEvent
{
    /**
     * 根据钩子ID查询事件
     *
     * @param int $hookid
     * @return array
     */
    public function select(int $hookid): array
    {
        $bllHook = new Hook();
        $hookinfo = $bllHook->find($hookid);
        if (!$hookinfo) {
            return [];
        }

        $hookevents =  Db::table('frame_hook_event')
            ->where('hook', '=', $hookinfo['ident'])
            ->get()
            ->map(function ($value) {
                return (array)$value;
            })
            ->toArray();
        $bllComponentEvent      = new ComponentEvent();
        $bllComponentEventMethod = new ComponentEventMethod();
        foreach ($hookevents as $key => $hookevent) {
            list($event, $class, $method)        = explode('/', $hookevent['event']);
            $eventinfo                           = $bllComponentEvent->findByIdent($event);
            $eventmethodinfo                     = $bllComponentEventMethod->findByPath($class . '/' . $method, $eventinfo['id']);
            $hookevents[$key]['eventinfo']       = $eventinfo;
            $hookevents[$key]['eventmethodinfo'] = $eventmethodinfo;
        }
        return $hookevents;
    }

    /**
     * 根据钩子IDENT 查询钩子执行事件
     *
     * @param string $ident
     * @return array
     */
    public function selectByHookIdent(string $ident): array
    {
        return Db::table('frame_hook_event')
            ->where('hook', '=', $ident)
            ->get()
            ->map(function ($value) {
                return (array)$value;
            })
            ->toArray();
    }

    /**
     * 根据事件组IDENT 查询钩子执行事件
     *
     * @param string $ident
     * @return array
     */
    public function selectByEventIdent(string $ident): array
    {
        return Db::table('frame_hook_event')
            ->where('event', 'like', $ident . '/')
            ->get()
            ->map(function ($value) {
                return (array)$value;
            })
            ->toArray();
    }
    /**
     * 根据HOOK event 查询
     *
     * @param string $hook
     * @param string $event
     * @return array
     */
    public function findHookAndEvent(string $hook, string $event): array
    {
        $data = Db::table('frame_hook_event')
            ->where('hook', '=', $hook)
            ->where('event', '=', $event)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }

    /**
     * 添加调用事件
     *
     * @param array $data 包含参数 eventid 和hookid的数组
     * @throws Exception
     * @return integer
     */
    public function add(array $data): int
    {
        //格式化数据
        try {
            $insertData = $this->_formatAddAndEditData($data);
        } catch (Exception $ex) {
            throw $ex;
        }

        //判断事件是否存在
        if ($this->findHookAndEvent($insertData['hook'], $insertData['event'])) {
            throw new Exception('事件已经存在');
        }

        return  Db::table('frame_hook_event')
            ->insertGetId($insertData);
    }

    /**
     * 删除调用事件
     *
     * @param integer $id
     * @return boolean
     */
    public function delete(int $id): bool
    {
        return  Db::table('frame_hook_event')
            ->where('id', '=', $id)
            ->delete();
    }

    private function _formatAddAndEditData(array $data): array
    {
        if (
            !isset($data['hookid'])
            || !isset($data['event_method_id'])
        ) {
            throw new Exception('参数错误');
        }


        $insertData = [];

        //获取钩子
        $bllHook            = new Hook();
        $hookinfo           = $bllHook->find($data['hookid']);
        $insertData['hook'] = $hookinfo['ident'];

        //获取事件
        list($eventid, $methodid)    = explode('_', $data['event_method_id']);

        $bllComponentEvent   = new ComponentEvent();
        $eventinfo           = $bllComponentEvent->find($eventid);
        $bllComponentEventMethod = new ComponentEventMethod();
        $methodinfo          = $bllComponentEventMethod->find($methodid);
        $insertData['event'] = $eventinfo['ident'] . '/' . $methodinfo['path'];


        //验证
        $ValidateHookEvent = new ValidateHookEvent();
        if (!$ValidateHookEvent->check($insertData)) {
            throw new Exception($ValidateHookEvent->getSimpleError());
        }

        return $insertData;
    }
}
